package cn.ilikes.tools.hbase.jpa.proxys.cglibs;

import java.lang.reflect.Method;

import javax.persistence.PersistenceException;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.NoOp;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.ilikes.tools.hbase.jpa.SysConfigs;
import cn.ilikes.tools.hbase.jpa.clients.AbClient;
import cn.ilikes.tools.hbase.jpa.metadatas.IEntityMetaData;
import cn.ilikes.tools.hbase.jpa.metadatas.elements.EntityFields;
import cn.ilikes.tools.hbase.jpa.proxys.LazyInitializers;
import cn.ilikes.tools.untils.HBaseUtils;

public class CglibLazyInitializer implements LazyInitializers, InvocationHandler {

	/** The Constant log. */
	private static final Log log = LogFactory.getLog(CglibLazyInitializer.class);

	private EntityFields entityFields;

	private IEntityMetaData targetEntityMetaData;

	private Object keyId;

	private AbClient client;

	private final CallbackFilter FINALIZE_FILTER = new CallbackFilter() {
		public int accept(Method method) {
			if (method.equals(targetEntityMetaData.getEntityId().getSetMethod()) || method.getName().equals("finalize")
					|| method.equals(targetEntityMetaData.getEntityId().getGetMethod()))
				return 1;

			for (EntityFields entityFields : targetEntityMetaData.getEntityFields().values()) {
				if (method.equals(entityFields.getSetMethod()) || method.equals(entityFields.getGetMethod()))
					return 0;
			}
			return 1;
		}
	};

	/**
	 * 
	 * @param entityFields
	 * @param entityMetaData
	 * @param keyId
	 * @param client
	 */
	public CglibLazyInitializer(EntityFields entityFields, IEntityMetaData targetEntityMetaData, Object keyId, AbClient client) {
		this.entityFields = entityFields;
		this.targetEntityMetaData = targetEntityMetaData;
		this.keyId = keyId;
		this.client = client;
	}

	@Override
	public Object getProxy() throws PersistenceException {
		try {
			Enhancer e = new Enhancer();
			e.setSuperclass(targetEntityMetaData.getEntityClazz());
			e.setInterfaces(targetEntityMetaData.getInterfaces());
			e.setCallbackTypes(new Class[] { InvocationHandler.class, NoOp.class });
			e.setCallbackFilter(FINALIZE_FILTER);
			e.setCallbacks(new Callback[] { this, NoOp.INSTANCE });
			e.setUseFactory(false);
			e.setInterceptDuringConstruction(false);
			Object object = e.create();
			Method method = targetEntityMetaData.getEntityId().getSetMethod();
			method.invoke(object, keyId);
			return object;
		} catch (Exception e) {
			throw new PersistenceException(e);
		}
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		EntityFields entityFields = selectByMethod(method);
		String columnName = entityFields.getjPAField().getColumnName();
		int index = columnName.indexOf(SysConfigs.hbase_column_family_qualifier);
		return client.findValue(targetEntityMetaData, keyId, entityFields.getField().getType(), HBaseUtils.getfamily(columnName, index), HBaseUtils.getQualifier(columnName, index));
		
	}

	private EntityFields selectByMethod(Method method) throws Throwable {
		for (EntityFields entityFields : targetEntityMetaData.getEntityFields().values()) {
//			System.out.println("======================================================")
			if (method.equals(entityFields.getGetMethod()) || method.equals(entityFields.getSetMethod()))
				return entityFields;
		}

		throw new Throwable("not find method : " + method.getName() + " 's EntityFields ");
	}

}
